package com.example.service.impl;

import com.example.common.AppResult;
import com.example.common.ResultCode;
import com.example.dao.UserMapper;
import com.example.exception.ApplicationException;
import com.example.model.User;
import com.example.service.IUserService;
import com.example.utils.MD5Util;
import com.example.utils.StringUtils;
import com.example.utils.UUIDUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: bjc
 * Date: 2025-10-04
 * Time: 17:56
 */
@Slf4j
@Service
public class UserServiceImpl implements IUserService {
    @Autowired
    private UserMapper userMapper;

    /**
     * 创建普通用户
     * 
     * @param user 用户信息
     */
    @Override
    public void createNormalUser(User user) {
        // 1.非空校验
        if (user == null || StringUtils.isEmpty(user.getUsername())
                || StringUtils.isEmpty(user.getPassword()) || StringUtils.isEmpty(user.getNickname()) ||
                StringUtils.isEmpty(user.getSalt())) {
            // 记录日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 2.按照用户名查询数据库中的用户信息
        User existsUser = userMapper.selectByUserName(user.getUsername());
        // 2.1.如果用户已存在，则抛出异常
        if (existsUser != null) {
            // 记录日志
            log.warn(ResultCode.FAILED_USER_EXISTS.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_EXISTS));
        }
        // 3.用户不存在，新增用户信息,设置用户属性默认值
        user.setGender((byte) 2);
        user.setArticleCount(0);
        user.setIsAdmin((byte) 0);
        user.setState((byte) 0);
        user.setDeleteState((byte) 0);
        // 设置日期
        Date date = new Date();
        user.setCreateTime(date);
        user.setUpdateTime(date);

        // 4.插入用户信息到数据库中
        int insertCount = userMapper.insertSelective(user);
        if (insertCount <= 0) {
            // 记录日志
            log.warn(ResultCode.FAILED_CREATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_CREATE));
        }
        log.info("用户注册成功，username=" + user.getUsername() + ".");
    }

    /**
     * 用户登录
     * 
     * @param username 用户名
     * @param password 密码
     * @return 用户信息
     */
    @Override
    public User login(String username, String password) {
        // 1.非空校验
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
            // 记录日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 2.按照用户名查询数据库中的用户信息
        User user = userMapper.selectByUserName(username);
        // 2.1.如果用户不存在，则抛出异常
        if (user == null) {
            // 记录日志
            log.warn(ResultCode.FAILED_USER_NOT_EXISTS + ",username = " + username + ".");
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_NOT_EXISTS));
        }
        // 3.判断密码是否正确
        // 3.1、根据盐值加密用户输入的密码
        String encryptPassword = MD5Util.md5Salt(password, user.getSalt());
        // 3.2、判断经过加密的密码和数据库中保存的密码是否一致
        if (!encryptPassword.equalsIgnoreCase(user.getPassword())) {// 注意要排除大小写
            // 记录日志
            log.warn(ResultCode.FAILED_LOGIN + "username=" + username + ",password=" + password + ".");
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_LOGIN));
        }
        // 4.校验成功，返回用户信息
        log.info("用户登录成功，username=" + username + ".");
        return user;
    }

    /**
     * 根据id查询用户信息
     * 
     * @param id 用户id
     * @return 用户信息
     */
    @Override
    public User selectById(Long id) {
        // 1.非空校验
        if (id == null) {
            // 记录日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 2.调用DAO层查询数据库获取对象
        return userMapper.selectByPrimaryKey(id);
    }

    /**
     * 根据用户id增加用户发帖数量
     * 
     * @param id 用户id
     */
    @Override
    public void addOneArticleCountById(Long id) {
        // 1.非空校验
        if (id == null || id <= 0) {
            // 打印日志
            log.warn(ResultCode.FAILED_BOARD_ARTICLE_COUNT.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_BOARD_ARTICLE_COUNT));
        }
        // 2.调用DAO层查询对应的板块信息
        User user = userMapper.selectByPrimaryKey(id);
        if (user == null) {
            // 打印日志
            log.warn(ResultCode.FAILED_USER_NOT_EXISTS.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_NOT_EXISTS));
        }
        // 3.更新帖子数量
        User updateUser = new User();
        updateUser.setId(user.getId());
        updateUser.setArticleCount(user.getArticleCount() + 1);
        int updateCount = userMapper.updateByPrimaryKeySelective(updateUser);
        if (updateCount != 1) {
            // 打印日志
            log.warn(ResultCode.FAILED + "，受影响的行数不等于1");
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED));
        }
    }

    /**
     * 根据用户id减少用户发帖数量
     * 
     * @param id 用户id
     */
    @Override
    public void subOneArticleCountById(Long id) {
        // 1.非空校验
        if (id == null || id <= 0) {
            // 打印日志
            log.warn(ResultCode.FAILED_BOARD_ARTICLE_COUNT.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_BOARD_ARTICLE_COUNT));
        }
        // 2.调用DAO层查询对应的板块信息
        User user = userMapper.selectByPrimaryKey(id);
        if (user == null) {
            // 打印日志
            log.warn(ResultCode.FAILED_USER_NOT_EXISTS.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_NOT_EXISTS));
        }
        // 3.更新帖子数量
        User updateUser = new User();
        updateUser.setId(user.getId());
        updateUser.setArticleCount(user.getArticleCount() - 1);
        if (updateUser.getArticleCount() < 0) {
            updateUser.setArticleCount(0);
        }
        // 4.更新数据库
        int updateCount = userMapper.updateByPrimaryKeySelective(updateUser);
        if (updateCount != 1) {
            // 打印日志
            log.warn(ResultCode.FAILED + "，受影响的行数不等于1");
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED));
        }
    }

    /**
     * 修改用户信息
     * 
     * @param user 用户信息
     */
    @Override
    public void modifyUserInfo(User user) {
        // 1.非空校验
        if (user == null || user.getId() == null || user.getId() <= 0) {
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 2.校验用户是否存在
        User existUser = userMapper.selectByPrimaryKey(user.getId());
        if (existUser == null) {
            // 打印日志
            log.warn(ResultCode.FAILED_USER_NOT_EXISTS.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_NOT_EXISTS));
        }
        // 3.定义一个标志位用来检测参数是否修改
        boolean checkAttr = false;// 表示没有校验通过
        // 4.定义一个用来更新的对象，防止用户传入的User对象中设置了其他属性，使用动态sql更新时，覆盖没有经过校验的字段
        User updateUser = new User();
        // 5.设置用户id
        updateUser.setId(user.getId());
        // 6.对每一个参数进行校验并赋值，校验用户名
        if (!StringUtils.isEmpty(user.getUsername()) && !user.getUsername().equals(existUser.getUsername())) {
            // 更新用户名时，需要进行唯一性检查
            User existUserByName = userMapper.selectByUserName(user.getUsername());
            if (existUserByName != null) {
                // 打印日志
                log.warn(ResultCode.FAILED_USER_EXISTS.toString());
                // 抛出异常
                throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_EXISTS));
            }
            // 数据库中没有相同用户名的用户，表示可以修改
            updateUser.setUsername(user.getUsername());
            checkAttr = true;
        }
        // 7.校验昵称
        if (!StringUtils.isEmpty(user.getNickname()) && !user.getNickname().equals(existUser.getNickname())) {
            updateUser.setNickname(user.getNickname());
            checkAttr = true;
        }
        // 8.校验性别
        if (user.getGender() != null && !user.getGender().equals(existUser.getGender())) {
            // 设置性别
            updateUser.setGender(user.getGender());
            // 合法性校验性别
            if (updateUser.getGender() > 2 || updateUser.getGender() < 0) {
                updateUser.setGender((byte) 2);
            }
            // 更新标志位
            checkAttr = true;
        }
        // 9.校验邮箱
        if (!StringUtils.isEmpty(user.getEmail()) && !user.getEmail().equals(existUser.getEmail())) {
            // 设置邮箱
            updateUser.setEmail(user.getEmail());
            // 更新标志位
            checkAttr = true;
        }
        // 10.校验手机号
        if (!StringUtils.isEmpty(user.getPhoneNum()) && !user.getPhoneNum().equals(existUser.getPhoneNum())) {
            // 设置手机号
            updateUser.setPhoneNum(user.getPhoneNum());
            // 更新标志位
            checkAttr = true;
        }
        // 11.校验个人简介
        if (!StringUtils.isEmpty(user.getRemark()) && !user.getRemark().equals(existUser.getRemark())) {
            // 设置个人简介
            updateUser.setRemark(user.getRemark());
            // 更新标志位
            checkAttr = true;
        }
        // 12.校验头像
        if (!StringUtils.isEmpty(user.getAvatarUrl()) && !user.getAvatarUrl().equals(existUser.getAvatarUrl())) {
            updateUser.setAvatarUrl(user.getAvatarUrl());
            checkAttr = true;
        }
        // 13.根据标志位判断是否需要更新
        if (!checkAttr) {
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 更新时间
        updateUser.setUpdateTime(new Date());
        // 14.更新数据库
        int updateCount = userMapper.updateByPrimaryKeySelective(updateUser);
        if (updateCount != 1) {
            // 打印日志
            log.warn(ResultCode.FAILED + "，受影响的行数不等于1");
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED));
        }

    }

    /**
     * 修改用户密码
     * 
     * @param id          用户id
     * @param newPassword 新密码
     * @param oldPassword 旧密码
     */
    @Override
    public void modifyUserPassword(Long id, String newPassword, String oldPassword) {
        // 1.根据用户id查询用户信息
        User user = userMapper.selectByPrimaryKey(id);
        // 2.判断用户是否存在
        if (user == null) {
            // 打印日志
            log.warn(ResultCode.FAILED_USER_NOT_EXISTS.toString());
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_USER_NOT_EXISTS));
        }
        // 3.判断旧密码是否正确
        // 获取用户盐值和旧密码组成密文
        String oldEncryptPassword = MD5Util.md5Salt(oldPassword, user.getSalt());
        if (!oldEncryptPassword.equals(user.getPassword())) {
            // 打印日志
            log.warn(ResultCode.FAILED_PARAMS_VALIDATE + ".username=" + user.getUsername() + ", oldPassword="
                    + oldPassword);
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED_PARAMS_VALIDATE));
        }
        // 4.生成新的盐值
        String newSalt = UUIDUtil.uuid32();
        // 5.生成新的密码密文
        String newEncryptPassword = MD5Util.md5Salt(newPassword, newSalt);
        // 6.创建用于更新的用户对象
        User updateUser = new User();
        updateUser.setId(id);// 设置用户id
        updateUser.setPassword(newEncryptPassword);// 设置密码密文
        updateUser.setSalt(newSalt);// 设置盐值
        updateUser.setUpdateTime(new Date());
        // 7.更新数据库
        int updateCount = userMapper.updateByPrimaryKeySelective(updateUser);
        if (updateCount != 1) {
            // 打印日志
            log.warn(ResultCode.FAILED + "，受影响的行数不等于1");
            // 抛出异常
            throw new ApplicationException(AppResult.failed(ResultCode.FAILED));
        }
        log.info("修改用户密码成功，用户id=" + id + ",用户名=" + user.getUsername());
    }
}
